package com.xsq.audio.player.utils;

import android.os.Handler;
import android.os.Looper;
import android.util.Log;

import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 自定义线程池，应用中共用
 */
public class ThreadPoolUtils {

    private static final String THREAD_POOL_PREFIX = "rs_player_thread_Pool";
    // CPU核数
    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    // 线程池中核心线程的数量
    private static final int CORE_POOL_SIZE = Math.min(1, Math.min(CPU_COUNT - 1, 4));
    // 线程池中最大线程数量
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
    // 非核心线程的超时时长
    private static final long KEEP_ALIVE_TIME = 30L;
    // 队列最多排队个数，可以控制线程创建的频率
    private static final int WAIT_COUNT = 128;

    private ThreadPoolExecutor pool;
    //UI主线程
    private static Thread mainThread;
    //主线程消息Handler
    private static Handler mainHandler;

    private ThreadPoolUtils(){
        createThreadPoolExecutor();

        Looper mainLooper = Looper.getMainLooper();
        mainThread = mainLooper.getThread();
        mainHandler = new Handler(mainLooper);
    }

    private static class RSThreadPoolInstance {
        private static final ThreadPoolUtils instance = new ThreadPoolUtils();
    }

    public static ThreadPoolUtils get(){
        return RSThreadPoolInstance.instance;
    }

    /**
     * 创建线程池
     */
    private ThreadPoolExecutor createThreadPoolExecutor() {
        pool = new ThreadPoolExecutor(
                CORE_POOL_SIZE,
                MAXIMUM_POOL_SIZE,
                KEEP_ALIVE_TIME,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(WAIT_COUNT),
                new ThreadPoolFactory(THREAD_POOL_PREFIX, Thread.NORM_PRIORITY - 2),
                new ThreadPoolHandlerException());
        return pool;
    }

    public void execute(Runnable runnable) {
        pool.execute(runnable);
    }

    public boolean removeRunnable(Runnable runnable) {
        return pool.remove(runnable);
    }

    public boolean isContainRunnable(Runnable runnable) {
        return pool.getQueue().contains(runnable);
    }

    /**
     * 当前线程是否是主线程
     */
    public boolean isOnMainThread() {
        return mainThread == Thread.currentThread();
    }

    /**
     * 在主线程中执行任务
     */
    public void runOnMainThread(Runnable r) {
        if (isOnMainThread()) {
            r.run();
        } else {
            mainHandler.post(r);
        }
    }

    public void postDelayed(Runnable runnable, long delayMillis) {
        mainHandler.postDelayed(runnable, delayMillis);
    }

    /**
     * 对runOnMainThread的，移除Runnable
     */
    public static void removeCallbackOnMainThread(Runnable r) {
        mainHandler.removeCallbacks(r);
    }

    /**
     * 创建线程工程
     */
    public static class ThreadPoolFactory implements ThreadFactory {
        private final AtomicInteger counter = new AtomicInteger(1);
        private String prefix = "";
        private int priority = Thread.NORM_PRIORITY;

        public ThreadPoolFactory(String prefix, int priority) {
            this.prefix = prefix;
            this.priority = priority;
        }

        public ThreadPoolFactory(String prefix) {
            this.prefix = prefix;
        }

        public Thread newThread(Runnable r) {
            Thread executor = new Thread(r, prefix + " #" + counter.getAndIncrement());
            executor.setDaemon(true);
            executor.setPriority(priority);
            return executor;
        }
    }

    /**
     * 任务异常拒绝策略
     */
    private class ThreadPoolHandlerException extends ThreadPoolExecutor.AbortPolicy {

        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {

            StringBuilder builder = new StringBuilder();
            Map<Thread, StackTraceElement[]> liveThreads = Thread.getAllStackTraces();
            for (Thread key : liveThreads.keySet()) {
                builder.append("Thread ").append(key.getName())
                        .append("\n");
                StackTraceElement[] trace = liveThreads.get(key);

                if (trace != null) {
                    for (StackTraceElement stackTraceElement : trace) {
                        builder.append("\tat ").append(stackTraceElement).append("\n");
                    }
                }
            }
            Log.e(THREAD_POOL_PREFIX, builder.toString());
            if (!pool.isShutdown()) {
                pool.shutdown();
                pool = null;
            }

            pool = createThreadPoolExecutor();
        }

    }

}
